/*-------------------------------------------------------------------------
 - Copyright (c) 2024-2025 [XD-AMCC TEAM]
 - [XD-AMCC] is licensed under Mulan PSL v2.
 - You can use this software according to the terms and conditions of the Mulan PSL v2.
 - You may obtain a copy of Mulan PSL v2 at:
 -          http://license.coscl.org.cn/MulanPSL2
 - THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES
 - OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
 - TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 - See the Mulan PSL v2 for more details.
 ------------------------------------------------------------------------*/


/**
 * @brief Inner operations of the class Parser.
 *
 * @author  WXQ#XDU
 * @date    2024.11
 */

#include "_parser_inner.h"

void parser_fetch_token (t_parser_ptr pThis) {
    pThis->pNextToken = tokenstream_consume(pThis->tokenStream);
}

bool parser_isTypename (t_parser_ptr pThis, int K) {
    t_token_ptr  pToken = NEXT_TOKEN_K(pThis, K);
    return token_is_type(pToken);
}

void enter_nonterminal (t_parser_ptr pThis,  EnumNonTerminal ntId,
                        t_tree_ptr root)
{
    if(amcc_is_logParerStack() ) {
        const char *ntName = nonterm_query_name(ntId);
        LOG_RDF_CALL("%.*s>>> ENTER  IN RDF %s , myRoot=%tx",
                     pThis->indent, amcc_long_spacestring(),
                     ntName,        root);
    }

    pThis->indent += 2;
    if ( pThis->maxCallDepth < (pThis->indent/2) )
        pThis->maxCallDepth = pThis->indent/2;
}

void exit_nonterminal (t_parser_ptr pThis,  EnumNonTerminal ntId,
                       t_tree_ptr root)
{
    if ( pThis->indent < 0 ) {
        ERROR_REPORT_BUG("Why parser.indent <= 0");
        pThis->indent = 0;
    } else if (pThis->indent > 0) {
        pThis->indent -= 2;
    }

    if (amcc_is_logParerStack() ) {
        const char *ntName = nonterm_query_name(ntId);
        LOG_RDF_CALL("%.*s<<< EXIT FROM RDF %s , myRoot=%tx",
                     pThis->indent, amcc_long_spacestring(),
                     ntName,        root);
    }
}


void parser_report_badtoken (t_parser_ptr   pThis,
                             t_token_ptr    tokenPtr,
                             EnumTokenKind  expectedByGrammar,
                             const char *   expectedDesc)
{
    t_position * pos = token_get_position(tokenPtr);
    ERROR_REPORT_INPUT(pos->filePath, pos->line, pos->column,
                       EC_TOKEN, token_get_text(tokenPtr),
                       (  (expectedDesc != NULL) ? expectedDesc
                             : token_sampleOfKind(expectedByGrammar)
//                           : token_nameOfKind(expectedByGrammar)
                       ) );
}


t_tree_ptr parser_match (t_parser_ptr   pThis,
                         EnumTokenKind  expectedByGrammar)
{
    EnumTokenKind inputTokenKind = LOOK_AHEAD(pThis);
    if (expectedByGrammar == inputTokenKind ) {
        t_token_ptr currentToken = NEXT_TOKEN(pThis);
        t_tree_ptr  tokTree = tree_new_leaf( NEXT_TOKEN(pThis) );
        parser_fetch_token(pThis);
        if ( NULL == tokTree ) {
            ERROR_REPORT_MALLOC();
            return NULL;
        }
        if(amcc_is_logParerStack() ) {
            t_token_ptr nextToken = NEXT_TOKEN(pThis);
            t_position_ptr currPos = token_get_position(currentToken);
            LOG_RDF_CALL ("%.*sMATCH token < %s , [%2d : %2d] , \"%s\" >"
                          ",\tnextToken is < %s , \"%s\" >",
                          pThis->indent, amcc_long_spacestring(),
                          token_get_kindName( currentToken ),
                          currPos->line,    currPos->column,
                          token_get_text( currentToken ),
                          token_get_kindName(nextToken ),
                          token_get_text( nextToken ) );
        }
        return tokTree;
    }

    parser_report_badtoken(pThis, pThis->pNextToken ,
                           expectedByGrammar, NULL);
    return NULL;
}


int parser_discard_tokens (t_parser_ptr pThis,
                           const EnumTokenKind * firstSet,
                           const EnumTokenKind * followSet)
{
    if (NULL == pThis)
        return 0;
    if (NULL == firstSet && NULL == followSet)
        return 0;

    if (NULL != firstSet) {
        do {   // waiting for a token in FIRST
            t_token_ptr currentToken = NEXT_TOKEN(pThis);
            t_position_ptr currPos = token_get_position(currentToken);
            LOG_RDF_CALL("%.*sDISCARD token < %-15s , [%2d : %2d] , \"%s\" >",
                         pThis->indent, amcc_long_spacestring(),
                         token_get_kindName(currentToken),
                         currPos->line, currPos->column,
                         token_get_text(currentToken));

            pThis->pNextToken = tokenstream_consume(pThis->tokenStream);
            EnumTokenKind  kind ;
            for (int k = 0; TK_ERROR != firstSet[k]; ++k) {
                kind = token_get_kind(pThis->pNextToken);
                if (TK_EOF == kind)  // EOF does not belong to any FIRST
                    return 0;
                if (firstSet[k] == kind)
                    return k + 1;
            }
        } while (true);
    }

    if (NULL != followSet) {
        do {   // waiting for a token in FOLLOW
            t_token_ptr currentToken = NEXT_TOKEN(pThis);
            t_position_ptr currPos = token_get_position(currentToken);
            LOG_RDF_CALL("%.*sDISCARD token < %-15s , [%2d : %2d] , \"%s\" >",
                         pThis->indent, amcc_long_spacestring(),
                         token_get_kindName(currentToken),
                         currPos->line, currPos->column,
                         token_get_text(currentToken));

            pThis->pNextToken = tokenstream_consume(pThis->tokenStream);
            EnumTokenKind kind;
            for (int k = 0; TK_ERROR != followSet[k]; ++k) {
                kind = token_get_kind(pThis->pNextToken);
                if (followSet[k] == kind)
                    return - k - 1;
                if (TK_EOF == kind)  // EOF may belong to FOLLOW
                    return 0;
            }
        } while (true);
    }

    return 0;
}